#include "userhandle.h"
#include <QDebug>
#include <QMessageBox>
#include <QVariant>
#include <QThread>
#include <QTimer>
#include <QNetworkInterface>

userhandle::userhandle(QObject *parent)
    : QObject{parent}
{
    QThread *thread1 = new QThread();
    this->m_opencv = new opencv();
    this->m_file = new file();
    this->m_http = new http("http://192.168.4.1/");
    this->m_effectedit = new effectedit();
    this->m_opencv->moveToThread(thread1);
    this->m_effectedit->moveToThread(thread1);
    thread1->start();

    // 设备在线检测
    QTimer *timer = new QTimer();
    connect(timer, &QTimer::timeout, this, [=](){
        QList<QHostAddress> hostList = QNetworkInterface::allAddresses();
        QStringList addressList;
        foreach(QHostAddress address, hostList) {
            if(address.protocol() == QAbstractSocket::IPv4Protocol)
                addressList.append(address.toString());
        }
        foreach(QString address, addressList) {
            if(address.contains("192.168.4.2")) {
                setDeviceState(true);
                return ;
            }
        }
        setDeviceState(false);
    });
    timer->start(1000);
}

userhandle::~userhandle()
{

}

bool userhandle::setLedColor(int ledPosition, QColor color)
{
    if(this->m_colorData.isEmpty()) {
        qDebug() << "led color data is empty";
        return false;
    }
    this->m_colorData.replace(ledPosition, color);
    return true;
}

QColor userhandle::getLedColor(int ledPosition)
{
    QColor color(0,0,0);
    if(this->m_colorData.isEmpty()) {
        qDebug() << "led color data is empty";
        return color;
    }
    color = this->m_colorData.at(ledPosition);
    return color;
}

void userhandle::setLedNum(int ledNum)
{
    this->m_ledNum = ledNum;
}

int userhandle::getLedNum()
{
    return this->m_ledNum;
}

void userhandle::setValidFrameNum(int validFrameNum)
{
    this->m_validFrameNum = validFrameNum;
}

int userhandle::getValidFrameNum()
{
    return this->m_validFrameNum;
}

void userhandle::setFrameRate(int frameRate)
{
    this->m_frameRate = frameRate;
}

int userhandle::getFrameRate()
{
    return this->m_frameRate;
}

void userhandle::setFrameWidth(int frameWidth)
{
    this->m_frameWidth = frameWidth;
}

int userhandle::getFrameWidth()
{
    return this->m_frameWidth;
}

void userhandle::setFrameHeight(int frameHeight)
{
    this->m_frameHeight = frameHeight;
}

int userhandle::getFrameHeight()
{
    return this->m_frameHeight;
}

void userhandle::setDeviceState(bool state)
{
    if(this->m_deviceState == state) {
        return ;
    }
    this->m_deviceState = state;
    emit deviceStateChanged(state);
}

QVariant userhandle::getFileList()
{
    return QVariant(this->m_file->getFileList());
}

void userhandle::setMyProperty(QString property, QVariant value)
{
    if(property == "lNum") { // ledNum
        setLedNum(value.toInt());
    } else if(property == "fValidNum") { // frameValidNum
        setValidFrameNum(value.toInt());
    } else if(property == "fRate") { // fRate
        setFrameRate(value.toInt());
    }
}

QVariant userhandle::getMyProperty(QString property)
{
    QVariant propertyValue;

    if(property == "fWidth") { // frameWidth
        propertyValue = getFrameWidth();
    } else if(property == "fHeight") { // frameHeight
        propertyValue = getFrameHeight();
    } else if(property == "fNum") { // frameNum
        propertyValue = this->m_opencv->getFrameNum();
    } else if(property == "fRate") { // frameRate
        propertyValue = getFrameRate();
    } else if(property == "fPath") { // filePath
        propertyValue = this->m_file->getFilePath();
    } else if(property == "lNum") { // ledNum
        propertyValue = getLedNum();
    } else if(property == "fValidNum") { // frameValidNum
        propertyValue = getValidFrameNum();
    }

    return propertyValue;
}

/************************import/process file******************************/
void userhandle::importAndOpenVideo(int mode)
{
    if(this->m_file->importFileVideo() == false) return;
    if(this->m_opencv->openVideo(this->m_file->getFilePath()) == false) return;
    setFrameWidth(this->m_opencv->getFrameWidth());
    setFrameHeight(this->m_opencv->getFrameHeight());
    setLedNum(getFrameWidth() / getFrameHeight() + (mode == 0 ? 1 : 0));
    this->m_imgData = this->m_opencv->getAllFrame(); // 获取所有帧图像
    setFrameRate(this->m_opencv->getFrameRate()); // 设置帧率
    emit videoFileOpened(this->m_file->getFilePath());
}

void userhandle::processVideo(int mode)
{
    if(getLedNum() == 0) {
        emit tipsShow("请先选择有效文件");
        return ;
    }
    this->m_colorData.clear();
    this->m_colorData = colorCalcAllFrame(mode);
    this->m_imgData.clear(); // 清空帧图片存储
//    qDebug() << "color list:" << this->m_colorData;
    emit videoFileProcessed();
}

void userhandle::importAndOpenLDFile()
{
    if(this->m_file->importFileLD() == false) return;
    if((this->m_file->getFileData().size() <= 10) || ((uchar)(this->m_file->getFileData().at(0)) != 1)) {
        emit tipsShow("ld文件数据存在错误");
        return ;
    }
    setLedNum((uchar)(this->m_file->getFileData().at(2)) | (ushort)(this->m_file->getFileData().at(3))<<8);
    setValidFrameNum((uchar)(this->m_file->getFileData().at(6)) | (ushort)(this->m_file->getFileData().at(7))<<8);
//    qDebug() << getLedNum() << getValidFrameNum();
    emit ldFileOpened();
}

void userhandle::processLDFile()
{
    // 移除前10个字节的配置信息 将其转换为QList<QColor>
    this->m_colorData.clear();
    this->m_colorData = QByteArrayToQColor(this->m_file->getFileData().remove(0,10));
    this->m_file->clearFileData(); // 清除存储的文件数据
//    qDebug() << "color list:" << this->m_colorData;
    emit ldFileProcessed();
}

void userhandle::importAndOpenFrames(int mode)
{
    if(this->m_file->importFramePicture() == false) return;
    int fileListCount = this->m_file->getFileList().count();
    for(int i = 0; i < fileListCount; i++) {
        this->m_imgData.append(QImage(this->m_file->getFilePath() + this->m_file->getFileList().at(i)));
    }
    setFrameWidth(this->m_imgData.at(0).size().width());
    setFrameHeight(this->m_imgData.at(0).size().height());
    setLedNum(getFrameWidth() / getFrameHeight() + (mode == 0 ? 1 : 0));

    emit framesOpened(fileListCount);
}

void userhandle::processFrames(int mode)
{
    if(getLedNum() == 0) {
        emit tipsShow("请先选择有效文件");
        return ;
    }
    this->m_colorData.clear();
    this->m_colorData = colorCalcAllFrame(mode);
    this->m_imgData.clear(); // 清空帧图片存储
    this->m_file->clearFileList();

    emit framesProcessed();
}

bool userhandle::createVideoFileLD()
{
    if(getLedNum() == 0) {
        emit tipsShow("请先导入有效素材");
        return false;
    }
    QByteArray byteArr;

    byteArr.clear();
    byteArr.append(createConfigData(1, getLedNum(), 0, getValidFrameNum(), 0));
    byteArr.append(QColorToQByteArray());

    this->m_file->createFileLD(byteArr);
    this->m_opencv->test01();

    qDebug() << "led num:" << getLedNum() << ",valid frame num:" << getValidFrameNum();
    return true;
}
/****************************color data***********************************/
QList<QColor> userhandle::colorCalcAllFrame(int mode)
{
    QList<QColor> colorData;
    colorData.clear();
    if(this->m_imgData.isEmpty())
    {
        qDebug() << "image list is empty";
        return colorData;
    }
    setValidFrameNum(this->m_imgData.count()); // 存储有效帧数

    for(int i = 0; i < this->m_imgData.count(); i++)
    {
        colorData.append(colorCalcOneFrame(this->m_imgData.at(i), getLedNum(), getFrameWidth(), getFrameHeight(), mode));
    }
//    qDebug() << "all frame:" << colorData;
    return colorData;
}

QList<QColor> userhandle::colorCalcOneFrame(QImage img, int ledNum, int width, int height, int mode)
{
    QList<QColor> colorData;
    colorData.clear();
    if(img.isNull())
    {
        setValidFrameNum(getValidFrameNum() - 1); // 有空图片则有效帧数减1
        qDebug() << "image is null";
        return colorData;
    }
    QColor color;
    int length = mode == 0 ? (width / (ledNum - 1)) : (width / ledNum);
    int centerX = mode == 0 ? 0 : (length >> 1);
    int centerY = height >> 1;
    int temp = 0;

    for(int i = 0; i < ledNum; i++)
    {
        temp = centerX + i * length;
//        qDebug() << "led:" << i << "(" << (temp >= width ? width - 1 : temp) << centerY << ")";
        color = img.pixelColor(temp >= width ? width - 1 : temp, centerY);
        colorData.append(color);
    }
//    qDebug() << "one frame:" << colorData;
    return colorData;
}

QByteArray userhandle::createConfigData(uchar chX, ushort ch1Num, ushort ch2Num, ushort ch1Frames, ushort ch2Frames)
{
    QByteArray byteArr;
    uchar data = 0;

    byteArr.append(chX);
    byteArr.append(data);
    byteArr.append((uchar)ch1Num);
    byteArr.append((uchar)(ch1Num >> 8));
    byteArr.append((uchar)ch2Num);
    byteArr.append((uchar)(ch2Num >> 8));
    byteArr.append((uchar)ch1Frames);
    byteArr.append((uchar)(ch1Frames >> 8));
    byteArr.append((uchar)ch2Frames);
    byteArr.append((uchar)(ch2Frames >> 8));

    return byteArr;
}

QByteArray userhandle::QColorToQByteArray()
{
    QByteArray byteArr;

    for(int i = 0; i < this->m_colorData.count(); i++)
    {
        byteArr.append(this->m_colorData.at(i).red());
        byteArr.append(this->m_colorData.at(i).green());
        byteArr.append(this->m_colorData.at(i).blue());
    }

    return byteArr;
}

QList<QColor> userhandle::QByteArrayToQColor(QByteArray byteArr)
{
    QList<QColor> colorList;
    int colorNum = this->getLedNum() * this->getValidFrameNum();

    for(int i = 0; i < colorNum; i++) {
        colorList.append(QColor((uchar)(byteArr.at(0 + i * 3)), (uchar)(byteArr.at(1 + i * 3)), (uchar)(byteArr.at(2 + i * 3))));
//        qDebug() << i << ":" << (uchar)(byteArr.at(0 + i * 3)) << (uchar)(byteArr.at(1 + i * 3)) << (uchar)(byteArr.at(2 + i * 3));
    }

    return colorList;
}
/******************************http******************************/
bool userhandle::uploadLedEffect(QString ledEffectNum)
{
    if(getLedNum() == 0) {
        emit tipsShow("请先导入有效素材");
        return false;
    }
    QByteArray byteArr;

    byteArr.clear();
    byteArr.append(createConfigData(1, getLedNum(), 0, getValidFrameNum(), 0));
    byteArr.append(QColorToQByteArray());
    this->m_http->httpPostHandle(byteArr, ledEffectNum.prepend("upload/"));

    return true;
}

void userhandle::getDeviceCANID(QString mode)
{
    if(strContains(mode, "private")) {
        this->m_http->httpGetHandle("privateid/");
    } else if(strContains(mode, "public")) {
        this->m_http->httpGetHandle("publicid/");
    }
}

void userhandle::setDeviceCANID(QString id, QString mode)
{
    bool ok;
    int hex = id.toInt(&ok, 16);
    if(!ok) {
        return ;
    }
    QByteArray byteArr;
    byteArr.clear();
    if(strContains(mode, "private")) {
        this->m_http->httpPostHandle(byteArr, QString("privateid/").append(QString::number(hex, 10)));
    } else if(strContains(mode, "public")) {
        this->m_http->httpPostHandle(byteArr, QString("publicid/").append(QString::number(hex, 10)));
    }
}

void userhandle::getDeviceVersions()
{
    this->m_http->httpGetHandle("versions/");
}

bool userhandle::strContains(QString src, QString target)
{
    return src.contains(target);
}

QStringList userhandle::httpResultHandle(QString ret, bool mode)
{
    QStringList strList;
    strList << "null" << "null";
    if(ret.indexOf(":") == -1)
    {
        return strList;
    }
    strList = ret.split(":");
    if(mode) {
        bool ok;
        int hex = strList[1].toInt(&ok, 10);
        strList[1] = QString::number(hex, 16).toUpper();
    }
    return strList;
}

void userhandle::updateDeviceVersions()
{
    if(this->m_file->importFileBin() == false) return ;
    this->m_http->httpPostHandle(this->m_file->getFileData(), "updata/");
}

void userhandle::previewLedEffect(QString effectID)
{
    QByteArray byteArr;
    byteArr.clear();
    this->m_http->httpPostHandle(byteArr, QString("preview/").append(effectID));
}

void userhandle::getHeartbeat()
{
    this->m_http->httpGetHandle("heartbeat/");
}

void userhandle::heartbeatHandle(QString ret)
{
    if(ret.contains("heartbeat")) this->m_deviceState = true;
    else this->m_deviceState = false;
}

/*******************************setting*******************************/
bool userhandle::saveOrCutFrame(int start, int end, QString mode)
{
    if(start == 0 || end == 0 || start > getValidFrameNum() || end > getValidFrameNum()) {
        emit tipsShow("帧数应>=1且<=总帧数");
        return false;
    }
    if(mode.contains("save")) {
        this->m_colorData.remove(end  * getLedNum(), this->m_colorData.count() - end  * getLedNum());
        this->m_colorData.remove(0, (start - 1) * getLedNum());
    } else if(mode.contains("cut")) {
        this->m_colorData.remove((start - 1) * getLedNum(), (end - start + 1) * getLedNum());
    }
    setValidFrameNum(this->m_colorData.count() / getLedNum());
    return true;
}

/*****************ledEffectEdit********************/

void userhandle::oneColor_create(QColor color)
{
    if(getLedNum() <= 0) return ;
    this->m_colorData.clear();
    this->m_colorData = this->m_effectedit->oneColor(getLedNum(), color);
    setValidFrameNum(this->m_colorData.count() / getLedNum());
}

void userhandle::sectionsRWL_create(int rwLedNum, int rwSpacing, int rwSections, int rwDelayFrame, QColor rwColor, QColor backColor)
{
    if(getLedNum() <= 0) return ;
    this->m_colorData.clear();
    this->m_colorData = this->m_effectedit->sectionsRWL(getLedNum(), rwLedNum, rwSpacing, rwSections, rwDelayFrame, rwColor, backColor);
    setValidFrameNum(this->m_colorData.count() / getLedNum());
}

